package cc.sends;

/**
 * @ Description : Banker Algorithm
 * @ Author : ChristosC
 * @ Date : 2020/12/4 19:13
 */
public class Main {
    private static final int n = 5;
    private static final int m = 3;
    private static int[] available = { 3, 3, 2 };
    private static int[][] max = { { 7, 5, 3 }, { 3, 2, 2 }, { 9, 0, 2 }, { 2, 2, 2 }, { 4, 3, 3 } };
    private static int[][] allocation = { { 0, 1, 0 }, { 2, 0, 0 }, { 3, 0, 2 }, { 2, 1, 1 }, { 0, 0, 2 } };
    private static int[][] need = { { 7, 4, 3 }, { 1, 2, 2 }, { 6, 0, 0 }, { 0, 1, 1 }, { 4, 3, 1 } };
    private static int[] request = new int[m];

    /**
     * Entrance For Program Start
     */
    public static void main(String[] args) {
        System.out.println("Judge System Security When Time Is t0:");
        if (securityAlgorithm()){
            System.out.println("When t0, System Is Safe.");
        }
        else {
            System.out.println("When t0, System Is Not Safe.");
        }

        //p1 request
        System.out.println("");
        request[0] = 1;
        request[1] = 0;
        request[2] = 2;
        bankerAlgorithm(request, 1);

        //p4 request
        System.out.println("");
        request[0] = 3;
        request[1] = 3;
        request[2] = 0;
        bankerAlgorithm(request, 4);

        //p0 request
        System.out.println("");
        request[0] = 0;
        request[1] = 2;
        request[2] = 0;
        bankerAlgorithm(request, 0);

        //Change p0 Request To (0,1,0)
        System.out.println("");
        System.out.println("In Book Page 123, If Change p0 Request To (0,1,0)");
        request[0] = 0;
        request[1] = 1;
        request[2] = 0;
        bankerAlgorithm(request, 0);
    }



    /**
    * @description: bankerAlgorithm
    * @param：[request, i]
    * @return void
    */
    public static void bankerAlgorithm(int request[], int i) {
        System.out.println("Process " + i + " Run BankerAlgorithm.");
        System.out.println("request");
        printOneMatrix(request);
        System.out.println("need");
        printOneMatrix(need[i]);

        if (compare(request, need[i])) {
            System.out.println("request <= need");
            System.out.println("request");
            printOneMatrix(request);
            System.out.println("available");
            printOneMatrix(available);

            if (compare(request, available)) {
                System.out.println("request <= available");
                available = oneMatrixSub(available, request);
                allocation[i] = oneMatrixAdd(allocation[i], request);
                need[i] = oneMatrixSub(need[i], request);


                if (securityAlgorithm()){
                    System.out.println("The System Is Safe, Can Allocate Resources To Process " + i);
                    System.out.println("available：");
                    printOneMatrix(available);
                }
                else {
                    System.out.println("The System Is Not Safe, Resources Will Not Allocate To Process " + i);
                    available = oneMatrixAdd(available, request);
                    allocation[i] = oneMatrixSub(allocation[i], request);
                    need[i] = oneMatrixAdd(need[i], request);
                    System.out.println("Process " + i + " Is Waiting.");
                    System.out.println("available：");
                    printOneMatrix(available);
                }
            }
            else {
                System.out.println("ERROR, request > available");
            }
        }
        else {
            System.out.println("ERROR, request > need");
        }
    }

    /**
    * @description: securityAlgorithm
    * @param：[]
    * @return boolean
    */
    public static boolean securityAlgorithm() {
        System.out.println("-----Run Security Algorithm-----");
        int[] work = new int[m];

        for (int i = 0; i < work.length; i++) {
            work[i] = available[i];
        }

        boolean[] finish = new boolean[n];
        for (int i = 0; i < finish.length; i++) {
            finish[i] = false;
        }
        int count = 0;

        for (int i = 0; i < n; i++) {
            if (compare(need[i], work) && !finish[i]){
                System.out.print("Process " + i + " Can Run.");
                work = oneMatrixAdd(work, allocation[i]);
                System.out.print("	 " + "Work + Allocation:");
                printOneMatrix(work);//This Work = Work + Allocation
                finish[i] = true;
                if (i == n - 1){
                    i = -1;
                }
            }
        }
        for (int j = 0; j < finish.length; j++){
            if (finish[j]) {
                count++;
            }
        }
        return count == n;
    }


    /**
    * @description: Two Matrix Subtract
    * @param：[first, second]
    * @return int[]
    */
    public static int[] oneMatrixSub(int[] first, int[] second) {
        for (int i = 0; i < first.length; i++) {
            first[i] = first[i] - second[i];
        }
        return first;
    }


    /**
    * @description: Two Matrix Summation
    * @param：[first, second]
    * @return int[]
    */
    public static int[] oneMatrixAdd(int[] first, int[] second) {
        for (int i = 0; i < first.length; i++) {
            first[i] = first[i] + second[i];
        }
        return first;
    }


    /**
    * @description: Compare Two Matrix, If The First Is Smaller Than The Second Or Equal, Return True;
    * @param：[first, second]
    * @return boolean
    */
    public static boolean compare(int[] first, int[] second) {
        int count = 0;
        for (int i = 0; i < first.length; i++) {
            if (first[i] <= second[i]) {
                count++;
            }
        }
        return count == first.length;
    }


    /**
    * @description: Print Matrix Details
    * @param：[temp]
    * @return void
    */
    public static void printOneMatrix(int[] temp) {
        for (int i = 0; i < temp.length; i++) {
            System.out.print(temp[i]);
            System.out.print("	");
        }
        System.out.println();
    }

}
